/*
* Author        Vo Tuan Anh
* Email         votuananhs@gmail.com
* Brief         This library controls the LCD 16x2, model 4 bit data.
*/

#include "lcd16x2_4bit.h"
#include "macro_lpc1768.h"


/*******************************************************************************
*
* Name          WriteDataToPort_LPC1768
* Brief         
* Paramater     
* Return        if OK is pass
*
*******************************************************************************/
uint8_t WriteDataToPort_LPC1768(uint32_t u32Data)
{
  GPIO_SetValue((uint8_t)PORT_LCD16X2, u32Data);
  GPIO_ClearValue((uint8_t)PORT_LCD16X2, ~u32Data);
  return OK;
}

/*******************************************************************************
*
* Name          CheckFlag_LCD16x2
* Brief         This function use for checking flag of lcd module.
*               It is busy or not busy ?
* Paramater     NA
* Return        if OK is pass, else FAIL is lcd is busy
*
*******************************************************************************/
uint8_t CheckFlag_LCD16x2(void)
{
  uint8_t u8Data;
  uint32_t u32Dir = (uint32_t)RS_LCD16X2 | (uint32_t)RW_LCD16X2 | (uint32_t)DIR_74HC245_LCD16X2;
  /* set direction for PORT_LCD16X2, set all pins is output */
  GPIO_SetDir(PORT_LCD16X2, u32Dir ,1);
  /* clear pin RS, set RW for write command */
  GPIO_SetValue((uint8_t)PORT_LCD16X2, (uint32_t)DIR_74HC245_LCD16X2);
  GPIO_ClearValue((uint8_t)PORT_LCD16X2, (uint32_t)RS_LCD16X2);
  GPIO_SetValue((uint8_t)PORT_LCD16X2, (uint32_t)RW_LCD16X2);
  
  u8Data = (uint8_t)ReadData4Bit_LCD16x2(); /* reading 4 bit high */
  u8Data |= (uint8_t)(ReadData4Bit_LCD16x2() >> 4); /* reading 4 bit low */
  
  if ((u8Data & (uint8_t)0x80) == (uint8_t)0x00)
    return ((uint8_t)OK);
  else
    return ((uint8_t)FAIL);
}

/*******************************************************************************
*
* Name          ReadData4Bit_LCD16x2
* Brief         This function use for reading 4 bit data from lcd module to microcontroller
* Paramater     NA
* Return        if ok, return value of lcd module (value contains 4 bit high)
*
*******************************************************************************/
uint8_t ReadData4Bit_LCD16x2(void)
{
  uint8_t u8OutData = 0x00;
  /* set direction for PORT_LCD16X2 */
  /* set pins is output */
  GPIO_SetDir((uint8_t)PORT_LCD16X2, ((uint32_t)EN_LCD16X2 | (uint32_t)DIR_74HC245_LCD16X2), 1);
  /* set pins is input */
  GPIO_SetDir((uint8_t)PORT_LCD16X2,(uint32_t)MASK_DATA_LCD16X2,0);  
  /* set pin EN of LCD 16x2 */  
  GPIO_SetValue((uint8_t)PORT_LCD16X2, (uint32_t)DIR_74HC245_LCD16X2);
  GPIO_SetValue((uint8_t)PORT_LCD16X2, (uint32_t)EN_LCD16X2);
  /* read data from LCD module */  
  GPIO_ClearValue((uint8_t)PORT_LCD16X2, (uint32_t)DIR_74HC245_LCD16X2);
  u8OutData = (uint8_t)((GPIO_ReadValue(PORT_LCD16X2) & (uint32_t)MASK_DATA_LCD16X2) >> (uint8_t)START_PIN);
  /* clear pin EN of LCD 16x2 */
  GPIO_SetValue((uint8_t)PORT_LCD16X2, (uint32_t)DIR_74HC245_LCD16X2);
  GPIO_ClearValue(PORT_LCD16X2, (uint32_t)EN_LCD16X2);
  /* return value */  
  return u8OutData;
}

/*******************************************************************************
*
* Name          WriteDate4Bit_LCD16x2
* Brief         This function use for writing 4 bit data from microcontroller to lcd module
* Paramater     
* Return        return OK, if this function is pass. Else return FAIL
*
*******************************************************************************/
uint8_t WriteData4Bit_LCD16x2(uint8_t u8Data)
{
  uint32_t u32Dir = (uint32_t)EN_LCD16X2 | (uint32_t)DIR_74HC245_LCD16X2 | (uint32_t)MASK_DATA_LCD16X2;
  uint32_t u32Data = (uint32_t)(u8Data << (uint8_t)START_PIN) | (uint32_t)EN_LCD16X2;
  /* set direction for PORT_LCD16X2, set all pins is output */
  GPIO_SetDir((uint8_t)PORT_LCD16X2,u32Dir,1);
  /* set direction for 74hc245 ic */
  GPIO_SetValue((uint8_t)PORT_LCD16X2, (uint32_t)DIR_74HC245_LCD16X2);
  /* set pin EN of LCD 16x2 */  
  GPIO_SetValue((uint8_t)PORT_LCD16X2, (uint32_t)EN_LCD16X2);
  /* write data to LCD module */
  WriteDataToPort_LPC1768(u32Data);  
  /* clear pin EN of LCD 16x2 */
  GPIO_ClearValue(PORT_LCD16X2, EN_LCD16X2);
  /* return OK for this function */
  return ((uint8_t)OK);
}

/*******************************************************************************
*
* Name          ReadData_LCD16x2
* Brief         This function use for reading data from lcd module to microcontroller
* Paramater     NA
* Return        if ok, return value of lcd module
*
*******************************************************************************/
uint8_t ReadData_LCD16x2(void)
{
  uint8_t u8OutData;
  uint32_t u32Dir = (uint32_t)RS_LCD16X2 | (uint32_t)RW_LCD16X2 | (uint32_t)DIR_74HC245_LCD16X2;
  /* set direction for PORT_LCD16X2, set all pins is output */
  GPIO_SetDir(PORT_LCD16X2, u32Dir,1);
  /* set pin RS, RW for write data */
  GPIO_SetValue((uint8_t)PORT_LCD16X2, (uint32_t)DIR_74HC245_LCD16X2);
  GPIO_SetValue((uint8_t)PORT_LCD16X2, (uint32_t)RS_LCD16X2);
  GPIO_SetValue((uint8_t)PORT_LCD16X2, (uint32_t)RW_LCD16X2);
  if ((uint8_t)OK == CheckFlag_LCD16x2())
  {
    u8OutData = (uint8_t)ReadData4Bit_LCD16x2(); /* reading 4 bit high */
    u8OutData |= (uint8_t)(ReadData4Bit_LCD16x2() >> 4); /* reading 4 bit low */
    
    return u8OutData;
  }
  else
    return ((uint8_t)FAIL);
}

/*******************************************************************************
*
* Name          WriteData_LCD16x2
* Brief         This function use for writing data from microcontroller to lcd module
* Paramater     Date is a variable contain value what is display on screen
* Return        return OK, if this function is pass. Else return FAIL
*
*******************************************************************************/
uint8_t WriteData_LCD16x2(uint8_t u8Data)
{
  uint8_t u8HighBit = (uint8_t)(u8Data & 0xf0);
  uint8_t u8LowBit = (uint8_t)((u8Data & 0x0f) << 4);
  uint32_t vDir = (uint32_t)RS_LCD16X2| (uint32_t)RW_LCD16X2 | (uint32_t)DIR_74HC245_LCD16X2;
  /* set direction for PORT_LCD16X2, set all pins is output */
  GPIO_SetDir((uint8_t)PORT_LCD16X2, vDir,1);
  /* set pin RS, clear RW for write data */
  GPIO_SetValue((uint8_t)PORT_LCD16X2, (uint32_t)DIR_74HC245_LCD16X2);
  GPIO_SetValue((uint8_t)PORT_LCD16X2, (uint32_t)RS_LCD16X2);
  GPIO_ClearValue((uint8_t)PORT_LCD16X2,(uint32_t)RW_LCD16X2);
  
  if ((uint8_t)OK == CheckFlag_LCD16x2())
  {
    /* writing 4 bit high */
    if ((uint8_t)OK != WriteData4Bit_LCD16x2(u8HighBit))
      return ((uint8_t)FAIL);
    /* writing 4 bit low */
    if ((uint8_t)OK != WriteData4Bit_LCD16x2(u8LowBit))
      return ((uint8_t)FAIL);
    /* return OK, if the WriteDate4Bit_LCD16x2 function is return OK */
    return ((uint8_t)OK);
  }
  else
    return ((uint8_t)FAIL);
}

/*******************************************************************************
*
* Name          WriteCommand_LCD16x2
* Brief         This function use for writing command from microcontroller to lcd module
* Paramater     Command is a variable contain value of command
* Return        return OK, if this function is pass. Else return FAIL
*
*******************************************************************************/
uint8_t WriteCommand_LCD16x2(uint8_t u8Command)
{
  uint8_t u8HighBit = (uint8_t)(u8Command & 0xf0);
  uint8_t u8LowBit = (uint8_t)((u8Command & 0x0f) << 4);
  uint32_t u32Dir = (uint32_t)RS_LCD16X2| (uint32_t)RW_LCD16X2 | (uint32_t)DIR_74HC245_LCD16X2;
  /* set direction for PORT_LCD16X2, set all pins is output */
  GPIO_SetDir((uint8_t)PORT_LCD16X2, u32Dir,1);
  /* clear pin RS, RW for write command */
  GPIO_SetValue((uint8_t)PORT_LCD16X2, (uint32_t)DIR_74HC245_LCD16X2);
  GPIO_ClearValue((uint8_t)PORT_LCD16X2, (uint32_t)RS_LCD16X2);
  GPIO_ClearValue((uint8_t)PORT_LCD16X2, (uint32_t)RW_LCD16X2);
  
  if ((uint8_t)OK == CheckFlag_LCD16x2())
  {
    /* writing 4 bit high */
    if ((uint8_t)OK != WriteData4Bit_LCD16x2(u8HighBit))
      return ((uint8_t)FAIL);
    /* writing 4 bit low */
    if ((uint8_t)OK != WriteData4Bit_LCD16x2(u8LowBit))
      return ((uint8_t)FAIL);
    /* return OK, if the WriteDate4Bit_LCD16x2 function is return OK */
    return ((uint8_t)OK);
  }
  else
    return ((uint8_t)FAIL);
}

/*******************************************************************************
*
* Name          PositionPoint_LCD16x2
* Brief         This function use for set position of point in LCD module
* Paramater     Pos_X and Pos_Y are positions
* Return        return OK, if this function is pass. Else return FAIL
*
*******************************************************************************/
uint8_t PositionPoint_LCD16x2(uint8_t u8Pos_X, uint8_t u8Pos_Y)
{
  uint8_t u8Pos;
  u8Pos = u8Pos_Y*64 + u8Pos_X;
  if ((uint8_t)OK == WriteCommand_LCD16x2(u8Pos))
    return ((uint8_t)OK);
  else
    return ((uint8_t)FAIL);
}

/*******************************************************************************
*
* Name          PrintString_LCD16x2
* Brief         This function use for printing a string in LCD module
* Paramater     - Pos_X and Pos_Y are positions the first of string
*               - And the first address of string on memory
* Return        return OK, if this function is pass. Else return FAIL
*
*******************************************************************************/
uint8_t PrintString_LCD16x2(uint8_t u8Pos_X, uint8_t u8Pos_Y, uint8_t *u8Str)
{
  PositionPoint_LCD16x2(u8Pos_X, u8Pos_Y);
  while(*u8Str)
  {
    if ((uint8_t)OK == WriteData_LCD16x2(*u8Str))
      u8Str++;
  }
  return OK;
}

/*******************************************************************************
*
* Name          InitMode4Bit_LCD16x2
* Brief         This function install paramater for LCD
* Paramater     NA
* Return        
*
*******************************************************************************/
uint8_t InitMode4Bit_LCD16x2(void)
{
  WriteCommand_LCD16x2(0x20);
  WriteCommand_LCD16x2(0x20);
  WriteCommand_LCD16x2(0x20);
  
  WriteCommand_LCD16x2(0x0e);
  WriteCommand_LCD16x2(0x06);
  
  WriteCommand_LCD16x2(0x01); /* H */
  return OK;
}
